
package com.city.parking.map;

import java.util.ArrayList;
import java.util.HashMap;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.baidu.mapapi.map.offline.MKOLSearchRecord;
import com.baidu.mapapi.map.offline.MKOLUpdateElement;
import com.baidu.mapapi.map.offline.MKOfflineMap;
import com.baidu.navisdk.util.logic.MapUtil;
import com.city.parking.ParkingApp;
import com.city.parking.R;
import com.city.parking.util.Utils;

@SuppressWarnings("rawtypes")
public class OfflineMapSettings extends Activity implements OnClickListener{
    public static final String TAG = "OfflineMapSettings";
    public static final String ACTION_BROADCAST_OFFLINE_MAP_STATE_UPDATE = "com.city.parking.map.ACTION_BROADCAST_OFFLINE_MAP_STATE_UPDATE";
    public static final int OFFLINE_MAP_STATE_REFRESH = 1;

    private ParkingApp app = null;
    private TextView cidView;
    private EditText cityNameView;
    private boolean isLocalList = false;

    private int mCityID = -1;

    private ArrayList<OfflineMapLocalItemModel> localList = null;
    private ArrayList<OfflineMapLocalItemModel> localDoneList = null;
    private ArrayList<MKOLUpdateElement> localRawList = null;
    private ListView localMapList = null;
    private HashMap<Integer, Integer> downloadInfoMap = new HashMap<Integer, Integer>();
    private HashMap<Integer, Boolean> subCityListStatusMap = new HashMap<Integer, Boolean>(); // true
                                                                                              // -
                                                                                              // expanded;
                                                                                              // false
                                                                                              // -
                                                                                              // collapsed
    private ListAdapter remoteListAdapter = null;
    private ListAdapter localListAdapter = null;
    private ArrayList<OfflineMapRemoteItemModel> remoteList = null;

    private OfflineMapUpdateReceiver myOfflineMapUpdateReceiver = null;
    
	private ServiceWaitThread mThread;
	private OfflineMapService mService = null;

	private void onServiceReady() {
		mService = OfflineMapService.get();
		mService.initOfflineMapInService();
		
		initView();
	}

	private class ServiceWaitThread extends Thread {
		public void run() {
			while (OfflineMapService.get() == null) {
				try {
					sleep(30);
				} catch (InterruptedException e) {
					throw new RuntimeException("waiting thread sleep() has been interrupted");
				}
			}

			mHandler.post(new Runnable() {
				@Override
				public void run() {
					onServiceReady();
				}
			});
			mThread = null;
		}
	}

	private void checkGeoService() {
		if (OfflineMapService.get() != null) {
			onServiceReady();
		} else {
			// start service as background  
			startService(new Intent().setClass(this, OfflineMapService.class));
			mThread = new ServiceWaitThread();
			mThread.start();
		}
	}

    

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {

            if (msg.what == LocalOfflineMapListAdapter.ACTION_CONFIRM_DELETE) {
                int cityID = msg.getData().getInt("city_id");
                showConfirmDialog(cityID);
            }
        }
    };

	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        app = (ParkingApp) this.getApplication();
        app.mOffline = new MKOfflineMap();

        requestWindowFeature(Window.FEATURE_NO_TITLE);

        setContentView(R.layout.activity_offline_map);

        checkGeoService();
    }

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		switch (v.getId()) {
		case R.id.nav_ico_back:
			finish();
			break;
		case R.id.nav_ico_more:
            isLocalList = !isLocalList;
            if (isLocalList) {
                openLocalMapList(v);
            } else {
            	openAllCityList(v);
            }
			break;

		default:
			break;
		}
	}

    private void initView() {
        ImageView back = (ImageView) findViewById(R.id.nav_ico_back);
        back.setOnClickListener(this);

        TextView title = (TextView) findViewById(R.id.nav_title);
        title.setVisibility(View.VISIBLE);
        title.setText(getString(R.string.som_title));

        ImageView more = (ImageView) findViewById(R.id.nav_ico_more);
        more.setOnClickListener(this);
        isLocalList = false;


        // Local Combined Map list
        localList = new ArrayList<OfflineMapLocalItemModel>();
        localDoneList = new ArrayList<OfflineMapLocalItemModel>();
        try {
            localRawList = app.mOffline.getAllUpdateInfo();
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (localRawList == null) {
            // localList = new ArrayList<MKOLUpdateElement>();
            if (ParkingApp.IS_DEBUG)
                Log.d(TAG, "local list is empty");
        } else {
            if (ParkingApp.IS_DEBUG)
                Log.d(TAG, "local map items: " + localRawList.size());
            downloadInfoMap.clear();
            for (MKOLUpdateElement localMapItem : localRawList) {
                if (ParkingApp.IS_DEBUG)
                    Log.d(TAG, "city: " + localMapItem.cityName + "|status: " + localMapItem.status);
                if (localMapItem.ratio < 100) {
                    localList.add(new OfflineMapLocalItemModel(localMapItem, false));
                } else {
                    localDoneList.add(new OfflineMapLocalItemModel(localMapItem, false));
                }
                downloadInfoMap.put(localMapItem.cityID, localMapItem.status);
            }
            // Download section
            if (localList.size() > 0) {
                if (ParkingApp.IS_DEBUG)
                    Log.d(TAG, "downloading city: " + localList.size());
                localList.add(
                        0,
                        new OfflineMapLocalItemModel(getResources().getString(
                                R.string.som_downloading)));
            }
            // Done section
            if (localDoneList.size() > 0) {
                if (ParkingApp.IS_DEBUG)
                    Log.d(TAG, "downloaded city: " + localDoneList.size());
                localList.add(new OfflineMapLocalItemModel(getResources().getString(
                        R.string.som_done_city)));
                for (int index = 0; index < localDoneList.size(); index++) {
                    localList.add(localDoneList.get(index));
                }
            }
        }

        localMapList = (ListView) findViewById(R.id.local_city_list);
        localListAdapter = new LocalOfflineMapListAdapter(this, localList, app, mHandler,
                this.downloadInfoMap);
        localMapList.setAdapter(localListAdapter);

        localMapList.setOnItemClickListener(new OnItemClickListener() {

            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                Log.v(TAG, "local item is clicked");
                if (localList.get(position).showActionBar()) {
                    localList.get(position).setActionBar(false);
                } else {
                    if (((LocalOfflineMapListAdapter) localListAdapter).lastActionBarItem != null) {
                        ((LocalOfflineMapListAdapter) localListAdapter).lastActionBarItem
                                .setActionBar(false);
                    }
                    localList.get(position).setActionBar(true);
                    ((LocalOfflineMapListAdapter) localListAdapter).lastActionBarItem = localList
                            .get(position);
                }
                ((ArrayAdapter) localListAdapter).notifyDataSetChanged();
            }
        });

        // Remote City List Combination
        ListView remoteCityList = (ListView) findViewById(R.id.remote_city_list);
        remoteList = new ArrayList<OfflineMapRemoteItemModel>();
        ArrayList<MKOLSearchRecord> recordsHot = app.mOffline.getHotCityList();
        ArrayList<MKOLSearchRecord> recordsCountry = app.mOffline.getOfflineCityList();

        // add hot city head
        remoteList
                .add(new OfflineMapRemoteItemModel(getResources().getString(R.string.som_hotcity)));

        if (recordsHot != null) {
            for (MKOLSearchRecord r : recordsHot) {
                if (downloadInfoMap.containsKey(r.cityID)) {
                    remoteList.add(new OfflineMapRemoteItemModel(r, downloadInfoMap.get(r.cityID),
                            false));
                } else {
                    remoteList.add(new OfflineMapRemoteItemModel(r, MKOLUpdateElement.UNDEFINED,
                            false)); // not
                                     // downloaded
                }
            }
        }

        // add country list head
        remoteList
                .add(new OfflineMapRemoteItemModel(getResources().getString(R.string.som_country)));

        if (recordsCountry != null) {
            for (MKOLSearchRecord r : recordsCountry) {
                if (downloadInfoMap.containsKey(r.cityID)) {
                    remoteList.add(new OfflineMapRemoteItemModel(r, downloadInfoMap.get(r.cityID),
                            false));
                } else {
                    remoteList.add(new OfflineMapRemoteItemModel(r, MKOLUpdateElement.UNDEFINED,
                            false)); // not
                                     // downloaded
                }
            }
        }

        remoteListAdapter = (ListAdapter) new RemoteOfflineMapListAdapter(this, remoteList);
        remoteCityList.setAdapter(remoteListAdapter);

        remoteCityList.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Log.v(TAG, "list item is clicked");
                OfflineMapRemoteItemModel clickedItem = remoteList.get(position);
                if (((clickedItem.getItemType() == 2) || (clickedItem.getItemType() == 0))
                        && (clickedItem.getDownloadStatus() != MKOLUpdateElement.FINISHED)) {
                    if (ParkingApp.network_status == ParkingApp.NO_NETWORK) {
                        Toast.makeText(OfflineMapSettings.this,
                                R.string.som_network_not_connected_error, Toast.LENGTH_SHORT)
                                .show();
                    } else {
                        mCityID = remoteList.get(position).getCityID();
                        mService.startOfflineMapDownload(mCityID);
                        downloadInfoMap.put(mCityID, MKOLUpdateElement.DOWNLOADING);
                        openLocalMapList(null);
                    }
                } else if (clickedItem.getItemType() == 1) {
                    if (subCityListStatusMap.containsKey(clickedItem.getCityID())
                            && (subCityListStatusMap.get(clickedItem.getCityID()))) {
                        subCityListStatusMap.put(clickedItem.getCityID(), false);
                        int subCityListSize = clickedItem.getSubCityListSize();
                        Log.v(TAG, "remove => sub city list size is " + subCityListSize);
                        for (int index = subCityListSize; index > 0; index--) {
                            remoteList.remove(position + index);
                        }
                    } else {
                        subCityListStatusMap.put(clickedItem.getCityID(), true);
                        int subCityListSize = clickedItem.getSubCityListSize();
                        Log.v(TAG, "add => sub city list size is " + subCityListSize);
                        for (int index = 0; index < subCityListSize; index++) {
                            if (downloadInfoMap
                                    .containsKey(clickedItem.getSubCityList().get(index).cityID)) {
                                remoteList.add(
                                        position + index + 1,
                                        new OfflineMapRemoteItemModel(clickedItem.getSubCityList()
                                                .get(index), downloadInfoMap.get(clickedItem
                                                .getSubCityList().get(index).cityID), true));
                            } else {
                                remoteList.add(position + index + 1, new OfflineMapRemoteItemModel(
                                        clickedItem.getSubCityList().get(index),
                                        MKOLUpdateElement.UNDEFINED, true));
                            }
                        }
                    }
                }

                ((ArrayAdapter) remoteListAdapter).notifyDataSetChanged();
            }
        });

        LinearLayout cl = (LinearLayout) findViewById(R.id.remote_list_layout);
        LinearLayout lm = (LinearLayout) findViewById(R.id.local_list_layout);
        lm.setVisibility(View.GONE);
        cl.setVisibility(View.VISIBLE);

    }

    public void openAllCityList(View view) {
    	((ImageView)findViewById(R.id.nav_ico_more)).setImageResource(R.drawable.nav_ico_setting);
    	
        LinearLayout cl = (LinearLayout) findViewById(R.id.remote_list_layout);
        LinearLayout lm = (LinearLayout) findViewById(R.id.local_list_layout);
        lm.setVisibility(View.GONE);
        cl.setVisibility(View.VISIBLE);
        updateRemoteListView();
    }

    public void openLocalMapList(View view) {
    	((ImageView)findViewById(R.id.nav_ico_more)).setImageResource(R.drawable.nav_ico_add);

        LinearLayout cl = (LinearLayout) findViewById(R.id.remote_list_layout);
        LinearLayout lm = (LinearLayout) findViewById(R.id.local_list_layout);
        lm.setVisibility(View.VISIBLE);
        cl.setVisibility(View.GONE);

        updateLocalListView();
    }

    public void search(View view) {
        ArrayList<MKOLSearchRecord> records = app.mOffline.searchCity(cityNameView.getText()
                .toString());
        if (records == null || records.size() != 1)
            return;
        cidView.setText(String.valueOf(records.get(0).cityID));
    }

    public void start(int cityid) {
        mCityID = cityid;
        boolean retVal = app.mOffline.start(cityid);
        if (ParkingApp.IS_DEBUG)
            Log.e(TAG, "offline map download start " + retVal);
        // clickLocalMapListButton(null);
        Toast.makeText(this, R.string.som_toast_map_download_start, Toast.LENGTH_SHORT).show();
    }

    public void stop(int cityid) {
        mCityID = cityid;
        app.mOffline.pause(cityid);
        Toast.makeText(this, R.string.som_toast_map_download_pause, Toast.LENGTH_SHORT).show();
    }

    public void remove(int cityid) {
        mCityID = cityid;
        app.mOffline.remove(cityid);
        Toast.makeText(this, R.string.som_toast_map_download_delete, Toast.LENGTH_SHORT).show();
    }

    public void importFromSDCard(View view) {
        int num = app.mOffline.importOfflineData();
        String msg = "";
        if (num == 0) {
            msg = getResources().getString(R.string.som_toast_map_import_from_sdcard_failed);
        } else {
            msg = getResources().getString(R.string.som_toast_map_import_from_sdcard_successful);
        }
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
    }

    public void updateRemoteListView() {
        remoteList.clear();
        ArrayList<MKOLSearchRecord> recordsHot = app.mOffline.getHotCityList();
        ArrayList<MKOLSearchRecord> recordsCountry = app.mOffline.getOfflineCityList();

        // update hot city status
        remoteList
                .add(new OfflineMapRemoteItemModel(getResources().getString(R.string.som_hotcity)));

        if (recordsHot != null) {
            for (MKOLSearchRecord r : recordsHot) {
                if (downloadInfoMap.containsKey(r.cityID)) {
                    remoteList.add(new OfflineMapRemoteItemModel(r, downloadInfoMap.get(r.cityID),
                            false));
                } else {
                    remoteList.add(new OfflineMapRemoteItemModel(r, MKOLUpdateElement.UNDEFINED,
                            false)); // not
                                     // downloaded
                }
            }
        }

        // add country list head
        remoteList
                .add(new OfflineMapRemoteItemModel(getResources().getString(R.string.som_country)));

        if (recordsCountry != null) {
            for (MKOLSearchRecord r : recordsCountry) {
                if (downloadInfoMap.containsKey(r.cityID)) {
                    remoteList.add(new OfflineMapRemoteItemModel(r, downloadInfoMap.get(r.cityID),
                            false));
                } else {
                    remoteList.add(new OfflineMapRemoteItemModel(r, MKOLUpdateElement.UNDEFINED,
                            false)); // not
                                     // downloaded
                }
            }
        }

        ((ArrayAdapter) remoteListAdapter).notifyDataSetChanged();
    }

    public void updateLocalListView() {
        try {
            localRawList = app.mOffline.getAllUpdateInfo();
        } catch (Exception e) {
            e.printStackTrace();
        }
        localDoneList.clear();
        localList.clear();
        if (localRawList == null) {
            // localList = new ArrayList<MKOLUpdateElement>();
        } else {
            downloadInfoMap.clear();
            for (MKOLUpdateElement localMapItem : localRawList) {
                if (localMapItem.ratio < 100) {
                    localList.add(new OfflineMapLocalItemModel(localMapItem, false));
                    downloadInfoMap.put(localMapItem.cityID, MKOLUpdateElement.DOWNLOADING);
                } else {
                    localDoneList.add(new OfflineMapLocalItemModel(localMapItem, false));
                    downloadInfoMap.put(localMapItem.cityID, MKOLUpdateElement.FINISHED);
                }

            }
            // Download section
            if (localList.size() > 0) {
                localList.add(
                        0,
                        new OfflineMapLocalItemModel(getResources().getString(
                                R.string.som_downloading)));
            }
            // Done section
            if (localDoneList.size() > 0) {
                localList.add(new OfflineMapLocalItemModel(getResources().getString(
                        R.string.som_done_city)));
                for (int index = 0; index < localDoneList.size(); index++) {
                    localList.add(localDoneList.get(index));
                }
            }
        }
        ((ArrayAdapter) localListAdapter).notifyDataSetChanged();
    }

    private void monitorOfflineMapUpdate() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(OfflineMapSettings.ACTION_BROADCAST_OFFLINE_MAP_STATE_UPDATE);
        myOfflineMapUpdateReceiver = new OfflineMapUpdateReceiver();
        registerReceiver(myOfflineMapUpdateReceiver, filter);
    }

    private class OfflineMapUpdateReceiver extends BroadcastReceiver {
        public void onReceive(Context context, Intent intent) {
            int type = intent.getIntExtra("type", -1);
            int state = intent.getIntExtra("state", -1);
            processOfflineMapUpdates(type, state);
        }
    }

    @Override
    protected void onPause() {

        // app.mOffline.pause(mCityID);
        // app.mMapView.onPause();
        unregisterReceiver(myOfflineMapUpdateReceiver);
        super.onPause();
    }

    @Override
    protected void onResume() {
        // app.mMapView.onResume();
        monitorOfflineMapUpdate();
        super.onResume();
    }

    public String formatDataSize(int size) {
        String ret = "";
        if (size < (1024 * 1024)) {
            ret = String.format("%dK", size / 1024);
        } else {
            ret = String.format("%.1fM", size / (1024 * 1024.0));
        }
        return ret;
    }

    @Override
    protected void onDestroy() {
        // app.mOffline.destroy();
        // app.mMapView.destroy();
        super.onDestroy();
        
        if (mService != null)
        	mService.tryQuitService();
    }

    private class OfflineMapTask extends AsyncTask<Integer, Integer, MKOLUpdateElement> {

        private int localState = -1;

        @Override
        protected void onPreExecute() {

        }

        @Override
        protected MKOLUpdateElement doInBackground(Integer... state) {

            MKOLUpdateElement update = app.mOffline.getUpdateInfo(state[0]);

            localState = state[0];

            return update;
        }

        @Override
        protected void onProgressUpdate(Integer... progresses) {

        }

        @Override
        protected void onPostExecute(MKOLUpdateElement updateInfo) {
            if (updateInfo != null) {
                if (updateInfo.ratio == 100) {
                    updateLocalListView();
                } else {
                    for (int index = 0; index < localList.size(); index++) {
                        if (localList.get(index).isGroupHeader) {
                            continue;
                        } else if (localList.get(index).getLocalItemInfo().cityID == localState) {
                            boolean actionbarStatus = localList.get(index).showActionBar();
                            localList.remove(index);
                            localList.add(index, new OfflineMapLocalItemModel(updateInfo,
                                    actionbarStatus));
                            break;
                        }
                    }
                    ((ArrayAdapter) localListAdapter).notifyDataSetChanged();
                }
            }
        }

        @Override
        protected void onCancelled() {

        }
    }

    private void processOfflineMapUpdates(int type, int state) {
        if (ParkingApp.IS_DEBUG)
            Log.e(TAG, "Type is " + type + ", state is " + state);
        switch (type) {
            case MKOfflineMap.TYPE_DOWNLOAD_UPDATE:
                new OfflineMapTask().execute(state);
                break;
            case MKOfflineMap.TYPE_NEW_OFFLINE:
                if (ParkingApp.IS_DEBUG)
                    Log.d(TAG, String.format("add offlinemap num:%d", state));
                break;
            case MKOfflineMap.TYPE_VER_UPDATE:
                // MKOLUpdateElement e = mOffline.getUpdateInfo(state);
                break;

            case OFFLINE_MAP_STATE_REFRESH:
                MKOLUpdateElement update = app.mOffline.getUpdateInfo(state);

                for (int index = 0; index < localList.size(); index++) {
                    if (localList.get(index).isGroupHeader) {
                        continue;
                    } else if (localList.get(index).getLocalItemInfo().cityID == state) {
                        boolean actionbarStatus = localList.get(index).showActionBar();
                        localList.remove(index);
                        localList.add(index, new OfflineMapLocalItemModel(update, actionbarStatus));
                        break;
                    }
                }
                ((ArrayAdapter) localListAdapter).notifyDataSetChanged();
                break;
        }

    }

    public void showConfirmDialog(final int cityID) {
        LayoutInflater factory = LayoutInflater.from(this);
        final View deleteDialogView = factory.inflate(R.layout.offline_map_delete_confirm_dialog,
                null);
        final AlertDialog deleteDialog = new AlertDialog.Builder(this).create();
        deleteDialog.setView(deleteDialogView);
        deleteDialogView.findViewById(R.id.button_yes).setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                deleteDialog.show();
                remove(cityID);
                deleteDialog.dismiss();
                downloadInfoMap.remove(cityID);
                updateLocalListView();
            }
        });
        deleteDialogView.findViewById(R.id.button_no).setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                deleteDialog.dismiss();

            }
        });

        deleteDialog.show();
    }

}
